import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { Roles } from "./roles.entity";
import { LogsService } from "../logs/logs.service";
import { LogLevel } from "../logs/logs.entity";
import { Menus } from "../menus/menu.entity";
import type { User } from "../user/user.entity";
import type { QueryRoleDto, CreateRoleDto } from "./dto";
import type { PaginatedData } from "../../types/api-response.interface";

/**
 * 角色服务 - 处理角色相关的业务逻辑
 */
@Injectable()
export class RolesService {
  constructor(
    @InjectRepository(Roles)
    private rolesRepository: Repository<Roles>,
    private readonly logsService: LogsService,
  ) {}

  /**
   * 查询所有角色（不分页）
   */
  async findAll(): Promise<Roles[]> {
    try {
      const roles = await this.rolesRepository.find({
        relations: ["users", "menus"],
        order: { id: "ASC" },
      });

      // 记录操作日志
      await this.logsService.createSystemLog(
        `查询所有角色（不分页），共找到 ${roles.length} 个角色`,
        LogLevel.INFO,
        "RolesService.findAll",
        { total: roles.length },
      );

      return roles;
    } catch (error) {
      // 记录错误日志
      await this.logsService.createErrorLog(error, "RolesService.findAll", undefined, {});
      throw new Error(`查询所有角色失败: ${error.message}`);
    }
  }

  /**
   * 分页查询角色列表，支持按名称搜索
   * @param queryDto 查询参数
   */
  async getPaginatedRoles(queryDto: QueryRoleDto = {}): Promise<PaginatedData<Roles>> {
    try {
      const { page = 1, pageSize = 10, name } = queryDto;
      const limit = pageSize;

      // 构建查询
      const queryBuilder = this.rolesRepository
        .createQueryBuilder("role")
        .leftJoinAndSelect("role.users", "user")
        .leftJoinAndSelect("role.menus", "menu");
      // 如果有名称搜索条件，添加模糊查询
      if (name && name.trim()) {
        queryBuilder.where("role.name LIKE :name", { name: `%${name.trim()}%` });
      }

      // 计算总数
      const total = await queryBuilder.getCount();

      // 添加分页
      const skip = (page - 1) * limit;
      queryBuilder.skip(skip).take(limit);

      // 添加排序
      queryBuilder.orderBy("role.id", "ASC");

      // 执行查询
      const roles = await queryBuilder.getMany();

      // 计算总页数
      const totalPages = Math.ceil(total / limit);

      // 记录操作日志
      await this.logsService.createSystemLog(
        `分页查询角色列表，页码: ${page}，每页: ${pageSize}，搜索关键词: ${name || "无"}，共找到 ${total} 个角色`,
        LogLevel.INFO,
        "RolesService.getPaginatedRoles",
        {
          page,
          pageSize,
          searchName: name,
          total,
          totalPages,
        },
      );

      return {
        list: roles,
        total,
        page,
        pageSize,
        totalPages,
      };
    } catch (error) {
      // 记录错误日志
      await this.logsService.createErrorLog(error, "RolesService.getPaginatedRoles", undefined, {
        queryParams: queryDto,
      });
      throw new Error(`查询角色列表失败: ${error.message}`);
    }
  }

  /**
   * 根据ID查找角色
   * @param id 角色ID
   */
  async findOne(id: number) {
    try {
      if (!id || id <= 0) {
        throw new Error("角色ID必须是正整数");
      }

      const role = await this.rolesRepository.findOne({
        where: { id },
        relations: ["users", "menus"],
      });

      if (!role) {
        throw new Error(`角色 ID ${id} 不存在`);
      }

      // 记录操作日志
      await this.logsService.createSystemLog(
        `根据ID查找角色: ${id}，角色名: ${role.name}`,
        LogLevel.INFO,
        "RolesService.findOne",
        { roleId: id },
      );

      return role;
    } catch (error) {
      // 记录错误日志
      await this.logsService.createErrorLog(error, "RolesService.findOne", undefined, { roleId: id });

      if (error.message.includes("角色ID必须是正整数") || error.message.includes("不存在")) {
        throw error;
      }
      throw new Error(`查找角色失败: ${error.message}`);
    }
  }

  /**
   * 创建新角色
   * @param createDto 角色创建信息
   */
  async create(createDto: CreateRoleDto) {
    try {
      if (!createDto.name) {
        throw new Error("角色名称不能为空");
      }

      // 检查角色名称是否已存在
      const existingRoleByName = await this.rolesRepository.findOne({
        where: { name: createDto.name },
      });

      if (existingRoleByName) {
        throw new Error(`角色名称 "${createDto.name}" 已存在`);
      }

      // 使用 Repository 的 create 方法创建实体实例
      const roleEntity = this.rolesRepository.create({ name: createDto.name });

      // 若传入菜单ID，关联菜单
      if (createDto.menuIds && Array.isArray(createDto.menuIds) && createDto.menuIds.length > 0) {
        const menuRepo = this.rolesRepository.manager.getRepository(Menus);
        const menus = await menuRepo.findByIds(createDto.menuIds);
        const foundIds = menus.map((m: any) => m.id);
        const missing = createDto.menuIds.filter((id) => !foundIds.includes(id));
        if (missing.length > 0) {
          throw new Error(`菜单 ID ${missing.join(", ")} 不存在`);
        }
        (roleEntity as any).menus = menus;
      }

      const newRole = await this.rolesRepository.save(roleEntity);

      // 记录操作日志
      await this.logsService.createSystemLog(
        `创建新角色成功: ${newRole.name} (ID: ${newRole.id})`,
        LogLevel.INFO,
        "RolesService.create",
        {
          newRoleId: newRole.id,
          roleName: newRole.name,
        },
      );

      return newRole;
    } catch (error) {
      // 记录错误日志
      await this.logsService.createErrorLog(error, "RolesService.create", undefined, {
        roleName: createDto.name,
      });

      if (error.message.includes("不能为空") || error.message.includes("已存在")) {
        throw error;
      }
      // 处理数据库唯一约束错误
      if (error.code === "ER_DUP_ENTRY") {
        throw new Error(`角色名称重复，无法创建`);
      }
      throw new Error(`创建角色失败: ${error.message}`);
    }
  }

  /**
   * 更新角色信息
   * @param id 角色ID
   * @param role 更新的角色信息
   */
  async update(id: number, role: Partial<Roles> & { menuIds?: number[] }) {
    try {
      if (!id || id <= 0) {
        throw new Error("角色ID必须是正整数");
      }

      // 检查角色是否存在
      const existingRole = await this.rolesRepository.findOne({
        where: { id },
      });

      if (!existingRole) {
        throw new Error(`角色 ID ${id} 不存在`);
      }

      // 排除关系字段，避免TypeORM类型错误
      const { users, menus, menuIds, ...updateData } = role;

      // 如果更新角色名称，检查是否重复
      if (updateData.name && updateData.name !== existingRole.name) {
        const duplicateRole = await this.rolesRepository.findOne({
          where: { name: updateData.name },
        });

        if (duplicateRole) {
          throw new Error(`角色名称 "${updateData.name}" 已存在`);
        }
      }

      // 先应用基本字段更新
      const result = await this.rolesRepository.update(id, updateData);

      // 如需更新菜单关系（覆盖式）
      if (Array.isArray(menuIds)) {
        const menuRepo = this.rolesRepository.manager.getRepository(Menus);
        const menus = menuIds.length > 0 ? await menuRepo.findByIds(menuIds) : [];
        const foundIds = menus.map((m: any) => m.id);
        const missing = menuIds.filter((mid) => !foundIds.includes(mid));
        if (missing.length > 0) {
          throw new Error(`菜单 ID ${missing.join(", ")} 不存在`);
        }

        const roleEntity = await this.rolesRepository.findOne({ where: { id }, relations: ["menus"] });
        if (!roleEntity) {
          throw new Error(`角色 ID ${id} 不存在`);
        }
        roleEntity.menus = menus;
        await this.rolesRepository.save(roleEntity);
      }

      if (result.affected === 0) {
        throw new Error(`更新角色失败，没有记录被修改`);
      }

      // 记录操作日志
      await this.logsService.createSystemLog(
        `更新角色信息成功: ${existingRole.name} (ID: ${id})`,
        LogLevel.INFO,
        "RolesService.update",
        {
          roleId: id,
          roleName: existingRole.name,
          updateFields: Object.keys(role),
        },
      );

      return result;
    } catch (error) {
      // 记录错误日志
      await this.logsService.createErrorLog(error, "RolesService.update", undefined, {
        roleId: id,
        updateFields: Object.keys(role),
      });

      if (
        error.message.includes("角色ID必须是正整数") ||
        error.message.includes("不存在") ||
        error.message.includes("已存在") ||
        error.message.includes("更新角色失败")
      ) {
        throw error;
      }
      // 处理数据库唯一约束错误
      if (error.code === "ER_DUP_ENTRY") {
        throw new Error(`角色名称已存在，无法更新`);
      }
      throw new Error(`更新角色失败: ${error.message}`);
    }
  }

  /**
   * 删除角色
   * @param id 角色ID
   */
  async remove(id: number) {
    try {
      // 参数验证
      if (!id || id <= 0) {
        throw new Error("角色ID必须是正整数");
      }

      // 先获取角色信息用于日志记录
      const existingRole = await this.rolesRepository.findOne({
        where: { id },
        relations: ["users"],
      });

      if (!existingRole) {
        throw new Error(`角色 ID ${id} 不存在`);
      }

      // 检查是否有用户关联此角色
      if (existingRole.users && existingRole.users.length > 0) {
        throw new Error(`无法删除角色 "${existingRole.name}"，还有 ${existingRole.users.length} 个用户关联此角色`);
      }

      const result = await this.rolesRepository.delete(id);

      // 记录操作日志
      await this.logsService.createSystemLog(
        `删除角色成功: ${existingRole.name} (ID: ${id})`,
        LogLevel.WARN,
        "RolesService.remove",
        {
          deletedRoleId: id,
          deletedRoleName: existingRole.name,
        },
      );

      return result;
    } catch (error) {
      // 记录错误日志
      await this.logsService.createErrorLog(error, "RolesService.remove", undefined, { roleId: id });

      // 处理自定义错误
      if (
        error.message.includes("角色ID必须是正整数") ||
        error.message.includes("不存在") ||
        error.message.includes("无法删除角色")
      ) {
        throw error;
      }

      // 捕获外键约束错误并转换为友好消息
      if (error.code === "ER_ROW_IS_REFERENCED_2") {
        throw new Error(`无法删除角色，存在用户关联数据。请先解除用户角色关联，或联系管理员处理。`);
      }

      // 处理其他数据库错误
      if (error.code) {
        throw new Error(`删除角色失败，数据库错误: ${error.message}`);
      }

      throw new Error(`删除角色失败: ${error.message}`);
    }
  }

  /**
   * 为角色添加用户
   * @param roleId 角色ID
   * @param userIds 用户ID数组
   */
  async addUsersToRole(roleId: number, userIds: number[]) {
    try {
      if (!roleId || roleId <= 0) {
        throw new Error("角色ID必须是正整数");
      }

      if (!userIds || !Array.isArray(userIds) || userIds.length === 0) {
        throw new Error("用户ID数组不能为空");
      }

      // 验证所有用户ID都是正整数
      const invalidIds = userIds.filter((id) => !id || id <= 0);
      if (invalidIds.length > 0) {
        throw new Error("所有用户ID必须是正整数");
      }

      // 查找角色（包含现有用户）
      const role = await this.rolesRepository.findOne({
        where: { id: roleId },
        relations: ["users"],
      });

      if (!role) {
        throw new Error(`角色 ID ${roleId} 不存在`);
      }

      // 查找要添加的用户
      const userRepository = this.rolesRepository.manager.getRepository("User");

      const usersToAdd = (await userRepository.findByIds(userIds)) as User[];

      if (usersToAdd.length !== userIds.length) {
        const foundIds = usersToAdd.map((u) => u.id);
        const notFoundIds = userIds.filter((id) => !foundIds.includes(id));
        throw new Error(`用户 ID ${notFoundIds.join(", ")} 不存在`);
      }

      // 过滤掉已经关联的用户
      const existingUserIds = role.users.map((u) => u.id);
      const newUsers = usersToAdd.filter((u) => !existingUserIds.includes(u.id));

      if (newUsers.length === 0) {
        throw new Error("所有指定用户都已关联到该角色");
      }

      // 添加新用户到角色
      role.users = [...role.users, ...newUsers];
      await this.rolesRepository.save(role);

      // 记录操作日志
      await this.logsService.createSystemLog(
        `为角色 "${role.name}" (ID: ${roleId}) 添加了 ${newUsers.length} 个用户`,
        LogLevel.INFO,
        "RolesService.addUsersToRole",
        {
          roleId,
          roleName: role.name,
          addedUserIds: newUsers.map((u) => u.id),
          addedUsernames: newUsers.map((u) => u.username),
        },
      );

      return {
        message: `成功为角色 "${role.name}" 添加了 ${newUsers.length} 个用户`,
        addedUsers: newUsers.map((u) => ({ id: u.id, username: u.username })),
      };
    } catch (error) {
      // 记录错误日志
      await this.logsService.createErrorLog(error, "RolesService.addUsersToRole", undefined, {
        roleId,
        userIds,
      });

      if (
        error.message.includes("必须是正整数") ||
        error.message.includes("不能为空") ||
        error.message.includes("不存在") ||
        error.message.includes("已关联")
      ) {
        throw error;
      }
      throw new Error(`为角色添加用户失败: ${error.message}`);
    }
  }

  /**
   * 从角色中移除用户
   * @param roleId 角色ID
   * @param userId 用户ID
   */
  async removeUserFromRole(roleId: number, userId: number) {
    try {
      if (!roleId || roleId <= 0) {
        throw new Error("角色ID必须是正整数");
      }

      if (!userId || userId <= 0) {
        throw new Error("用户ID必须是正整数");
      }

      // 查找角色（包含用户）
      const role = await this.rolesRepository.findOne({
        where: { id: roleId },
        relations: ["users"],
      });

      if (!role) {
        throw new Error(`角色 ID ${roleId} 不存在`);
      }

      // 查找要移除的用户
      const userIndex = role.users.findIndex((u) => u.id === userId);
      if (userIndex === -1) {
        throw new Error(`用户 ID ${userId} 未关联到角色 "${role.name}"`);
      }

      const removedUser = role.users[userIndex];

      // 从角色中移除用户
      role.users.splice(userIndex, 1);
      await this.rolesRepository.save(role);

      // 记录操作日志
      await this.logsService.createSystemLog(
        `从角色 "${role.name}" (ID: ${roleId}) 中移除了用户 "${removedUser.username}" (ID: ${userId})`,
        LogLevel.INFO,
        "RolesService.removeUserFromRole",
        {
          roleId,
          roleName: role.name,
          removedUserId: userId,
          removedUsername: removedUser.username,
        },
      );

      return {
        message: `成功从角色 "${role.name}" 中移除用户 "${removedUser.username}"`,
        removedUser: { id: removedUser.id, username: removedUser.username },
      };
    } catch (error) {
      // 记录错误日志
      await this.logsService.createErrorLog(error, "RolesService.removeUserFromRole", undefined, {
        roleId,
        userId,
      });

      if (
        error.message.includes("必须是正整数") ||
        error.message.includes("不存在") ||
        error.message.includes("未关联")
      ) {
        throw error;
      }
      throw new Error(`从角色中移除用户失败: ${error.message}`);
    }
  }

  /**
   * 获取角色下的所有用户
   * @param roleId 角色ID
   */
  async getRoleUsers(roleId: number) {
    try {
      if (!roleId || roleId <= 0) {
        throw new Error("角色ID必须是正整数");
      }

      const role = await this.rolesRepository.findOne({
        where: { id: roleId },
        relations: ["users"],
      });

      if (!role) {
        throw new Error(`角色 ID ${roleId} 不存在`);
      }

      // 记录操作日志
      await this.logsService.createSystemLog(
        `查询角色 "${role.name}" (ID: ${roleId}) 的用户列表，共 ${role.users.length} 个用户`,
        LogLevel.INFO,
        "RolesService.getRoleUsers",
        {
          roleId,
          roleName: role.name,
          userCount: role.users.length,
        },
      );

      return {
        role: { id: role.id, name: role.name },
        users: role.users.map((u) => ({ id: u.id, username: u.username })),
        total: role.users.length,
      };
    } catch (error) {
      // 记录错误日志
      await this.logsService.createErrorLog(error, "RolesService.getRoleUsers", undefined, { roleId });

      if (error.message.includes("必须是正整数") || error.message.includes("不存在")) {
        throw error;
      }
      throw new Error(`查询角色用户失败: ${error.message}`);
    }
  }

  /**
   * 设置角色的用户列表（覆盖式更新）
   * @param roleId 角色ID
   * @param userIds 用户ID数组
   */
  async setRoleUsers(roleId: number, userIds: number[]) {
    try {
      if (!roleId || roleId <= 0) {
        throw new Error("角色ID必须是正整数");
      }

      if (!Array.isArray(userIds)) {
        throw new Error("用户ID必须是数组格式");
      }

      // 验证所有用户ID都是正整数（允许空数组）
      if (userIds.length > 0) {
        const invalidIds = userIds.filter((id) => !id || id <= 0);
        if (invalidIds.length > 0) {
          throw new Error("所有用户ID必须是正整数");
        }
      }

      // 查找角色
      const role = await this.rolesRepository.findOne({
        where: { id: roleId },
        relations: ["users"],
      });

      if (!role) {
        throw new Error(`角色 ID ${roleId} 不存在`);
      }

      let newUsers: any[] = [];
      if (userIds.length > 0) {
        // 查找要设置的用户
        const userRepository = this.rolesRepository.manager.getRepository("User");

        newUsers = (await userRepository.findByIds(userIds)) as User[];

        if (newUsers.length !== userIds.length) {
          const foundIds = newUsers.map((u) => u.id);
          const notFoundIds = userIds.filter((id) => !foundIds.includes(id));
          throw new Error(`用户 ID ${notFoundIds.join(", ")} 不存在`);
        }
      }

      const oldUserCount = role.users.length;

      // 覆盖式更新用户列表
      role.users = newUsers;
      await this.rolesRepository.save(role);

      // 记录操作日志
      await this.logsService.createSystemLog(
        `设置角色 "${role.name}" (ID: ${roleId}) 的用户列表，从 ${oldUserCount} 个用户更新为 ${newUsers.length} 个用户`,
        LogLevel.INFO,
        "RolesService.setRoleUsers",
        {
          roleId,
          roleName: role.name,
          oldUserCount,
          newUserCount: newUsers.length,
          newUserIds: newUsers.map((u) => u.id),
        },
      );

      return {
        message: `成功设置角色 "${role.name}" 的用户列表`,
        role: { id: role.id, name: role.name },
        users: newUsers.map((u) => ({ id: u.id, username: u.username })),
        total: newUsers.length,
      };
    } catch (error) {
      // 记录错误日志
      await this.logsService.createErrorLog(error, "RolesService.setRoleUsers", undefined, {
        roleId,
        userIds,
      });

      if (
        error.message.includes("必须是正整数") ||
        error.message.includes("必须是数组格式") ||
        error.message.includes("不存在")
      ) {
        throw error;
      }
      throw new Error(`设置角色用户列表失败: ${error.message}`);
    }
  }
}
